package com.thx.common.struts2;

import com.opensymphony.xwork2.Preparable;
import com.thx.common.log.annotation.Log;
import com.thx.common.log.annotation.LogId;
import com.thx.common.service.BaseManager;
import com.thx.common.util.ReflectUtils;
import com.thx.common.util.ReflectionUtils;
import com.thx.common.web.ActionResult;
import com.thx.common.web.Page;
import com.thx.common.web.PropertyFilter;
import com.thx.common.web.SearchResult;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.List;

/**
 * 通用增删改查固定到 Action 里, 让大家采用一样的格式.
 *
 * @author 贾红磊
 */
public class CurdAction<T> extends BaseAction implements Preparable {

  private static final long serialVersionUID = -7422181840556256043L;
  // 通用跳转
  protected static final String LIST = "list";
  protected static final String ADD = "add";
  protected static final String EDIT = "edit";
  protected static final String REMOVE = "remove";
  protected static final String SAVE = "save";
  protected static final String VIEW = "view";

  protected Page<T> page;// 翻页信息

  protected String id; // 实体类的主键ID
  private Class<T> entityClass; // T的反射类型
  protected T entity; // T类型对象
  protected List<T> list; // 页面列表list

  protected String[] delId;// checkBox多条记录进行删除时用到

  @Autowired(required = false)
  protected BaseManager<T> baseMgr;

  /**
   * 在构造函数中利用反射机制获得参数T的具体类.
   */
  public CurdAction() {
    this.entityClass = ReflectUtils.getClassGenricType(getClass());
    getModel();
  }

  /**
   * Action的默认执行方法.
   */
  @Override
  public String execute() {
    try {
      doList();
    } catch (Exception ex) {
      ex.printStackTrace();
      logger.error(ex.getMessage(), ex);
    }
    return SUCCESS;
  }

  /**
   * Action的默认执行方法.
   */
  public String list() {
    try {
      doList();
    } catch (Exception ex) {
      ex.printStackTrace();
      logger.error(ex.getMessage(), ex);
    }
    return LIST;
  }

  /**
   * 进入新增或修改页面.
   */
  @Override
  public String input() {
    try {
      doInput();
    } catch (Exception ex) {
      ex.printStackTrace();
      logger.error(ex.getMessage(), ex);
    }
    return INPUT;
  }

  /**
   * 进入查看页面.
   */
  public String view() {
    try {
      doView();
    } catch (Exception ex) {
      ex.printStackTrace();
      logger.error(ex.getMessage(), ex);
    }
    return VIEW;
  }

  /**
   * 新增或修改.
   */
  @Log(action = "edit")
  public String save() {
    try {
      doSave();
      // 添加后给ID赋值
      getLogId();
    } catch (Exception ex) {
      ex.printStackTrace();
      logger.error(ex.getMessage(), ex);
    }
    return JSON;
  }

  /**
   * 删除一条记录.
   */
  @Log(action = "delete")
  public String delete() {
    try {
      doDelete();
    } catch (Exception ex) {
      setResult(ActionResult.FAIL, "删除失败！");
      ex.printStackTrace();
      logger.error(ex.getMessage(), ex);
    }
    return JSON;
  }

  /**
   * 批量删除.
   */
  @Log(action = "delete", multiField = "delId")
  public String delMulti() {
    try {
      doDelMulti();
    } catch (Exception ex) {
      setResult(ActionResult.FAIL, "删除失败！");
      ex.printStackTrace();
      logger.error(ex.getMessage(), ex);
    }

    return JSON;
  }

  /**
   * execute回调方法，处理进入主页面的相关逻辑，可在子类中覆盖此方法.
   */
  protected void doList() throws Exception {
    int start = page.getStart();
    int max = page.getMax();
    list = baseMgr.paginList(start, max);
    int count = baseMgr.paginCount();
    page.setCount(count);
  }

  /**
   * input回调方法，处理进入新增或修改页面前的相关逻辑，可在子类中覆盖此方法.
   */
  protected void doInput() throws Exception {
    prepareEntity();
  }

  /**
   * view回调方法，处理进入查看页面的相关逻辑，可在子类中覆盖此方法.
   */
  protected void doView() throws Exception {
    if (StringUtils.isNotBlank(id)) {
      entity = baseMgr.get(id);
    }
  }

  /**
   * save回调方法，处理保存的相关逻辑，可在子类中覆盖此方法.
   */
  protected void doSave() throws Exception {
    try {
      if (StringUtils.isBlank(id)) {
        setResult(ActionResult.SUCCESS, "添加成功！");
      } else {
        setResult(ActionResult.SUCCESS, "修改成功！");
      }
      baseMgr.save(entity);
    } catch (Exception ex) {
      if (StringUtils.isBlank(id)) {
        setResult(ActionResult.FAIL, "添加失败！");
      } else {
        setResult(ActionResult.FAIL, "修改失败！");
      }
      logger.error(ex.getMessage(), ex);
    }
  }

  /**
   * delete回调方法，处理删除相关逻辑，可在子类中覆盖此方法.
   */
  protected void doDelete() throws Exception {
    if (StringUtils.isNotBlank(id)) {
      baseMgr.delete(id);
      setResult(ActionResult.SUCCESS, "删除成功！");
    }
  }

  /**
   * delMulti回调方法，处理批量删除逻辑，可在子类中覆盖此方法.
   */
  protected void doDelMulti() throws Exception {
    if (delId != null && delId.length > 0) {
      baseMgr.delMulti(delId);
      setResult(ActionResult.SUCCESS, "删除成功！");
    }
  }

  /**
   * 拦截器 prepare 会在执行对应的list方法前调用本方法.
   */
  public void prepareList() throws Exception {

  }

  /**
   * 拦截器 prepare 会在执行对应的Input方法前调用本方法.
   */
  public void prepareInput() throws Exception {
  }

  /**
   * 拦截器 prepare 会在执行对应的save方法前调用本方法.
   */
  public void prepareSave() throws Exception {

  }

  /**
   * 拦截器 prepare 会在执行对应的view方法前调用本方法.
   */
  public void prepareView() throws Exception {

  }

  protected void prepareEntity() throws Exception {
    if (StringUtils.isNotBlank(id)) {
      entity = baseMgr.get(id);
    }
  }

  /**
   * 翻页查询完成后需要调用次方法结束翻页的最后设置.
   *
   * @param searchData 由service层返回的查询结果
   */
  protected List<T> completePage(SearchResult<T> searchData) {
    int count = searchData.getCount();
    page.setCount(count);
    return searchData.getItems();
  }

  /**
   * ModelDriven接口定义的方法，返回实体对象.
   */
  public T getModel() {
    if (entity == null) {
      try {
        entity = entityClass.newInstance();
      } catch (InstantiationException ex) {
        logger.error("给泛型实体赋值异常，class=" + entityClass.getName(), ex);
      } catch (IllegalAccessException ex) {
        logger.error("给泛型实体赋值异常，class=" + entityClass.getName(), ex);
      }
    }
    return entity;
  }

  /**
   * 页面列表显示的list.
   */
  public List<T> getList() {
    return list;
  }

  /**
   * 获取页面传递的id值.
   *
   * @param id 主键ID
   */
  public void setId(String id) {
    this.id = id;
  }

  /**
   * Preparable接口的方法，设置为空方法体是屏蔽它去拦截所有的方法.
   */
  public void prepare() throws Exception {
  }

  protected List<PropertyFilter> doFilter() throws Exception {
    List<PropertyFilter> filters = PropertyFilter.buildFromHttpRequest(Struts2Utils.getRequest());
    // 设置默认排序方式
    if (!page.isOrderBySetted()) {
      page.setOrderBy("id");
      page.setOrder(Page.DESC);
    }
    return filters;
  }

  private void getLogId() {
    String logId = "0";
    Field[] fields = entityClass.getDeclaredFields();
    for (Field field : fields) {
      Annotation annotation = field.getAnnotation(LogId.class);
      if (null != annotation) {
        Object fid = ReflectionUtils.getFieldValue(entity, field.getName());
        if (fid == null || fid.toString().equals("0")) {
          // 原来不知道为啥这么写，先空着好了
        } else {
          logId = fid.toString();
        }
      }
    }
    id = logId;
  }

  public Page<?> getPage() {
    return this.page;
  }

  public void setPage(Page page) {
    this.page = page;
  }

  public T getEntity() {
    return entity;
  }

  public void setEntity(T entity) {
    this.entity = entity;
  }

  public void setDelId(String[] delId) {
    this.delId = delId;
  }

  /**
   * 获取 ID.
   */
  public String getId() {
    if (id == null || "".equals(id)) {
      return "";
    } else {
      return id;
    }
  }
}
